/**
* @author: Lu
* @date: 2021.02.19
* @brief: 接收带外数据的服务端程序
* @note: 有些传输层协议具有带外数据的概念，用于迅速通知对方本端发生的重要事件，因此，带外数据比普通数据(也称带内数据)拥有更高的优先级。
*		 带外数据总是被立即发送，而不论发送缓冲区是否有排队等待发送的普通数据，带外数据的传输可以使用一条独立的传输层连接，也可以映射到传输普通数据的
*		 连接中，UDP和TCP并没有真正的带外数据，不过TCP可以利用其头部中的紧急指针标志和紧急指针两个字段，给应用程序提供了一种紧急方式，TCP使用传输普通数据
*		 的连接来传输紧急数据，这种紧急数据可带外数据的含义类似
*/
#include<signal.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

#define BUF_SIZE 1024
int main(int argc,char* argv[])
{
	if(argc <= 2)
	{
		printf("usage: %s ip_address port_number\n",basename(argv[0]));
		return 1;
	}

	const char* ip = argv[1];
	int port = atoi(argv[2]);

	//创建服务器端d套接字并初始化
	int serverSock = socket(AF_INET,SOCK_STREAM,0);
	assert(serverSock>=0);

	struct sockaddr_in serverSockAddr;
	bzero(&serverSockAddr,sizeof(serverSockAddr));
	serverSockAddr.sin_family = AF_INET;
	inet_pton(AF_INET,ip,&serverSockAddr.sin_addr);
	serverSockAddr.sin_port = htons(port);

	int ret;
	ret = bind(serverSock,(struct sockaddr*)&serverSockAddr,sizeof(serverSockAddr));
	assert(ret != -1);

	ret = listen(serverSock,5);
	assert(ret != -1);

	printf("Init Successful!\n");
	printf("Waiting Connection..\n");

	//接收连接
	struct sockaddr_in clientSockAddr;
	socklen_t clientAddrLength;
	int connfd = accept(serverSock,(struct sockaddr*)&clientSockAddr,&clientAddrLength);
	if(connfd < 0)
	{
		printf("errno is:%d\n",errno);
	}
	else
	{
		char buf[BUF_SIZE];

		memset(buf,'\0',BUF_SIZE);
		ret = recv(connfd,buf,BUF_SIZE-1,0);
		printf("got %d bytes of normal data '%s'\n",ret,buf);

		memset(buf,'\0',BUF_SIZE);
		ret = recv(connfd,buf,BUF_SIZE-1,0);
		printf("got %d bytes of oop data '%s'\n",ret,buf);

		memset(buf,'\0',BUF_SIZE);
		ret = recv(connfd,buf,BUF_SIZE-1,0);
		printf("got %d bytes of normal data '%s'\n",ret,buf);

		close(connfd);
	}
	//关闭服务端套接字
	close(serverSock);
	return 0;
}
